#include "tracker.h"

#define MAX_FILE_COUNT 1024

int main(int argc, char** argv)
{
  // global data init

  globalTrackerData = createTrackerData();

  assert(argc >= 2);
  int PORT_TRACKER = atoi(argv[1]);
  pthread_t threads[MAX_CLIENT];
  int connectionState[MAX_CLIENT];
  int nextConnection = 0; 
  int socketFd = socket(AF_INET, SOCK_STREAM, TCP_PROTOCOL_NUMBER);
  initArray(connectionState,MAX_CLIENT,0);
  if (socketFd == -1)
    {
      perror("socket()");
      exit(0);
    }
  struct sockaddr_in sin;
  sin.sin_addr.s_addr = htonl(INADDR_ANY);
  sin.sin_family = AF_INET;
  sin.sin_port = htons(PORT_TRACKER);
  if (bind(socketFd, (struct sockaddr*) &sin, sizeof(sin)) == -1)
    {
      perror("bind()");
      exit(0);
    }
  if (listen(socketFd, MAX_CLIENT) == -1)
    {
      perror("listen()");
      exit(0);
    }
  while(42)
    {
      LG("Tracker listening on port %d\n", PORT_TRACKER);
      if (waitForConnection(socketFd, connectionState, nextConnection, threads))
	{
	  connectionState[nextConnection] = 1;
	  nextConnection = getNextConnectionId(connectionState, MAX_CLIENT);
	  if ( nextConnection == -1 )
	    {
	      while(nextConnection == -1)
		nextConnection = getNextConnectionId(connectionState, MAX_CLIENT);
	    }
	}
    }
   
  return 0;
}

trackerData* createTrackerData()
{
  trackerData* td = malloc(sizeof(trackerData));
  td->fileList = createTable(MAX_FILE_COUNT);
  td->peerList = NULL;
  return td;
}

void freeTrackerData(trackerData* td)
{
  freeTable(td->fileList);
  while(td->peerList != NULL)
    {
      td->peerList = removeElementList(td->peerList);
    }
}

void addFileToTrackerData(char* fileHash, file* fileInfo)
{
  addData(fileHash, (void*) fileInfo, globalTrackerData->fileList);
}

void addSeederForFile(char* fileHash, peer* seeder)
{
  DBG("adding seeder %s:%s for file %s\n", seeder->ip, seeder->port, fileHash);
  file* f = (file*) getData(fileHash, globalTrackerData->fileList);
  if (f != NULL)
    {
      if(!existSeederInList(seeder, f->seeders))
	f->seeders = addElementToList( (void*) seeder, f->seeders);
      else
	{
	  DBG("%s","Seeder already know for this file\n");
	}
    }
  else
    {
      WG("%s","unknown key in addSeederForFile\n");
    }
}

void dumpPeerList(list* l)
{
  list* temp = l;
  while(temp != NULL)
    {
      peer* p = (peer*) temp->data;
      DBG("\t%s:%s\n", p->ip, p->port);
      temp = (list*) temp->next;
    }
}

void dumpTrackerData()
{
  #ifdef DEBUG
  DBG("%s","Dumping fileList Hashtable\n");
  int i;
  for (i=0;i<globalTrackerData->fileList->nbItem;i++)
    {
      file* f = (file*) globalTrackerData->fileList->dataArray[i];
      DBG("FILE %s (%s, %d, %d)\n",
	     globalTrackerData->fileList->keyArray[i],
	     f->fileName, f->length, f->pieceSize);
      DBG("%s","\tSEEDERS :\n"); 
      dumpPeerList(f->seeders);
    }
  DBG("%s","Dumping peerList\n");
  dumpPeerList(globalTrackerData->peerList);
  #endif
}

int existSeederInList(peer* p, list* l)
{
  while(l!=NULL)
    {
      peer* p2 = (peer*)(l->data);
      if (strcmp(p->ip, p2->ip) == 0 && strcmp(p->port, p2->port) == 0)
	return 1;
      l = l->next;
    }
  return 0;
}
